home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / Apps / DevTools / eText5 / Source / Kludges.subproj / KeyDownBrowser.m < prev    next >
Encoding:
Text File  |  1994-11-04  |  9.9 KB  |  391 lines

  1. //---------------------------------------------------------------------------------------------------------
  2. //
  3. //    KeyDownBrowser
  4. //
  5. //    Inherits From:        NXBrowser
  6. //
  7. //    Declared In:        KeyDownBrowser.h
  8. //
  9. //    Disclaimer
  10. //
  11. //        You may freely copy, distribute and reuse this software and its
  12. //        associated documentation. I disclaim any warranty of any kind, 
  13. //        expressed or implied, as to its fitness for any particular use.
  14. //
  15. //---------------------------------------------------------------------------------------------------------
  16. #import "KeyDownBrowser.h"
  17. #import "KeyDownMatrix.h"
  18.  
  19.  
  20. #define RETURN        13
  21. #define LEFTARROW    172
  22. #define UPARROW    173
  23. #define RIGHTARROW    174
  24. #define DOWNARROW    175
  25. #define DELETE    127
  26.  
  27. #define CHUNK         64
  28.  
  29.  
  30. @implementation KeyDownBrowser
  31.  
  32. //---------------------------------------------------------------------------------------------------------
  33. //     Timed Entry Methods (Private)
  34. //---------------------------------------------------------------------------------------------------------
  35. void Search (timedEntry, now, self)
  36.     DPSTimedEntry    timedEntry;
  37.     double            now;
  38.     void*            self;
  39. {
  40.     [(id)self perform: @selector (_search)];
  41. }
  42.  
  43.  
  44. - _addTimedEntry
  45. {
  46.         timedEntry = DPSAddTimedEntry (inputTimeOut, Search, (void*) self,         NX_MODALRESPTHRESHOLD);
  47.         NXPing();
  48.         return self;
  49. }
  50.  
  51.  
  52. - _removeTimedEntry
  53. {
  54.     if ( ! timedEntry) return self;
  55.     DPSRemoveTimedEntry (timedEntry);
  56.     timedEntry = 0;
  57.     return self;
  58. }
  59.  
  60.  
  61. //---------------------------------------------------------------------------------------------------------
  62. //     Miscellaneous Methods (Private)
  63. //---------------------------------------------------------------------------------------------------------
  64. - _chunk
  65. {
  66.     //  Allocate memory for input buffer.
  67.     
  68.     if ( ! searchString)
  69.         searchString = NX_MALLOC (searchString, char, CHUNK);
  70.     else
  71.         searchString = NX_REALLOC (searchString, char, strlen(searchString) + CHUNK);
  72.         
  73.     if ( ! searchString) NXLogError ("Out of Memory in _chunk!");
  74.     return self;
  75. }
  76.  
  77.  
  78. - _selectCellInRow:(int)aRow ofMatrix:aMatrix andDoClick:(BOOL)doClick
  79. {
  80.     [aMatrix selectCellAt: aRow :0];
  81.     [aMatrix scrollCellToVisible: aRow :0];
  82.     if (doClick) [self doClick: aMatrix];
  83.     return self;
  84. }
  85.  
  86.  
  87. //---------------------------------------------------------------------------------------------------------
  88. //     Search Methods (Private)
  89. //---------------------------------------------------------------------------------------------------------
  90. - (int) _searchColumn
  91. {
  92.     //  If there is no selection within the browser, return column 0.  If there are multiple selections
  93.     //  return the current selected column.  If there is 1 selection, then if it is a leaf, return the 
  94.     //  current selected column.  If it is a branch, return the current selected column + 1.
  95.     
  96.     id    selectedCellList;
  97.     int    searchColumn = [self selectedColumn];
  98.     
  99.     if (searchColumn < 0) return 0;
  100.  
  101.     if ([self isMultipleSelectionEnabled])
  102.         {
  103.         selectedCellList = [self getSelectedCells: nil];
  104.         if ([selectedCellList count] == 1) 
  105.             if ([[selectedCellList objectAt: 0] isLeaf] == NO)
  106.                 searchColumn++;
  107.         selectedCellList = [selectedCellList free];
  108.         return searchColumn;
  109.         }
  110.         
  111.     if ([self selectedCell])
  112.         if ([[self selectedCell] isLeaf] == NO) searchColumn++;
  113.         
  114.     return searchColumn;
  115. }
  116.  
  117.  
  118. - _search
  119. {
  120.     //  Searches current search column for first occurrence of searchString.
  121.     
  122.     int        iterator;
  123.     int        searchColumn = [self _searchColumn];
  124.     id        matrix = [self matrixInColumn: searchColumn];
  125.     id        currentCell;
  126.     BOOL    found = NO;
  127.     
  128.     [self _removeTimedEntry];
  129.  
  130.     for (iterator = 0; iterator < [matrix numRows]; iterator++)
  131.         {
  132.         currentCell = [matrix cellAt: iterator :0];
  133.         if (NXOrderStrings([currentCell stringValue], searchString, 
  134.             wantsCaseSensitiveSearch, strlen (searchString), NULL) == 0)
  135.             {
  136.             [matrix selectCellAt: -1 :-1];
  137.             [self _selectCellInRow:iterator ofMatrix:matrix andDoClick:YES];
  138.             found = YES;
  139.             break;
  140.             }
  141.         }
  142.     
  143.     if (! found) NXBeep();
  144.     memset (searchString, 0, strlen (searchString));
  145.     return self;
  146. }
  147.  
  148.  
  149. //---------------------------------------------------------------------------------------------------------
  150. //     Key Down Methods (Private)
  151. //---------------------------------------------------------------------------------------------------------
  152. - _upArrow: (NXEvent *) theEvent
  153. {
  154.     id    matrix;
  155.     int    selectedRow;
  156.     int    selectedColumn = [self selectedColumn];
  157.     
  158.     if (selectedColumn == -1) return self;
  159.     matrix = [self matrixInColumn:selectedColumn];
  160.     selectedRow = [matrix selectedRow] - 1;
  161.     if (selectedRow < 0) selectedRow = 0;
  162.     [self _selectCellInRow:selectedRow ofMatrix:matrix andDoClick:YES];
  163.     return self;
  164. }
  165.  
  166.  
  167. - _downArrow: (NXEvent *) theEvent
  168. {
  169.     id    matrix;
  170.     int    selectedRow;
  171.     int    selectedColumn = [self selectedColumn];
  172.     
  173.     if (selectedColumn == -1) return self;
  174.     matrix = [self matrixInColumn: selectedColumn];
  175.     selectedRow = [matrix selectedRow] + 1;
  176.     if (selectedRow > [matrix numRows] - 1) selectedRow = [matrix numRows] - 1;
  177.     [self _selectCellInRow:selectedRow ofMatrix:matrix andDoClick:YES];
  178.     return self;
  179. }
  180.  
  181.  
  182. - _leftArrow: (NXEvent *) theEvent
  183. {
  184.     id    matrix;
  185.     int    selectedColumn = [self selectedColumn];
  186.     
  187.     if (selectedColumn == -1) return self;
  188.     matrix = [self matrixInColumn: selectedColumn];
  189.     [self setLastColumn: selectedColumn];
  190.     [matrix selectCellAt: -1 :-1];
  191.     [matrix sendAction:action to:target];
  192.     if (selectedColumn == 0) return self;
  193.     selectedColumn -= 1;
  194.     matrix = [self matrixInColumn: selectedColumn];
  195.     if ([self firstVisibleColumn] > selectedColumn) [self scrollColumnsRightBy: 1];
  196.     [matrix scrollCellToVisible: [matrix selectedRow] :[matrix selectedCol]];
  197.     return self;
  198. }
  199.  
  200.  
  201. - _rightArrow: (NXEvent *) theEvent
  202. {
  203.     id matrix = [self matrixInColumn: ([self selectedColumn] + 1)];
  204.     if (! matrix) return self;
  205.     [self _selectCellInRow:0 ofMatrix:matrix andDoClick:YES];
  206.     return self;
  207. }
  208.  
  209.  
  210. - _return: (NXEvent *) theEvent
  211. {
  212.     int    selectedColumn = [self selectedColumn];
  213.     
  214.     if (selectedColumn == -1) return self;
  215.     [self doDoubleClick: [self matrixInColumn:selectedColumn]];
  216.     return self;
  217. }
  218.  
  219.  
  220. //---------------------------------------------------------------------------------------------------------
  221. //     Initialization
  222. //---------------------------------------------------------------------------------------------------------
  223. - initFrame: (const NXRect *) frameRect
  224. {
  225.     //  Give it default IB characteristics, set the Matrix class, enable keys.
  226.     
  227.     [super initFrame: frameRect];
  228.     [self setMatrixClass: [KeyDownMatrix class]];
  229.     [self separateColumns: YES];
  230.     [self setHorizontalScrollerEnabled: YES];
  231.     [self setEmptySelectionEnabled: YES];
  232.     [self setTitle: "KeyDownBrowser" ofColumn: 0];
  233.     [self acceptArrowKeys:YES andSendActionMessages:YES];
  234.     [self wantsCaseSensitiveSearch: NO];
  235.     [self inputTimeOut: 0.5];
  236.     [self _chunk];
  237.     memset (searchString, 0, CHUNK);
  238.     return self;
  239. }
  240.  
  241.  
  242. - free
  243. {
  244.     [self _removeTimedEntry];
  245.     if (searchString) free (searchString);
  246.     return self = [super free];
  247. }
  248.  
  249.  
  250. //---------------------------------------------------------------------------------------------------------
  251. //     Accessors
  252. //---------------------------------------------------------------------------------------------------------
  253. - wantsCaseSensitiveSearch: (BOOL) aFlag
  254. {
  255.     wantsCaseSensitiveSearch = aFlag;
  256.     return self;
  257. }
  258.  
  259.  
  260. - (BOOL) wantsCaseSensitiveSearch
  261. {
  262.     return wantsCaseSensitiveSearch;
  263. }
  264.  
  265.  
  266. - inputTimeOut: (float) aFloat
  267. {
  268.     inputTimeOut = aFloat;
  269.     return self;
  270. }
  271.  
  272.  
  273. - (float) inputTimeOut
  274. {
  275.     return inputTimeOut;
  276. }
  277.  
  278.  
  279. //---------------------------------------------------------------------------------------------------------
  280. //     Event Handling
  281. //---------------------------------------------------------------------------------------------------------
  282. - mouseDown: (NXEvent*) theEvent
  283. {
  284.     if ([self isEnabled] == NO) return self;
  285.     [super mouseDown: theEvent];
  286.     [[self window] makeFirstResponder: self] ;
  287.     return self;
  288. }
  289.  
  290.  
  291. - keyDown: (NXEvent *) theEvent
  292. {
  293.     if ([self isEnabled] == NO) return self;
  294.         
  295.     [self _removeTimedEntry];
  296.  
  297.     switch (theEvent->data.key.charCode)
  298.         {
  299.         case UPARROW:
  300.             [self _upArrow: theEvent];
  301.             break;
  302.         case DOWNARROW:
  303.             [self _downArrow: theEvent];
  304.             break;
  305.         case LEFTARROW:
  306.             [self _leftArrow: theEvent];
  307.             break;
  308.         case RIGHTARROW:
  309.             [self _rightArrow: theEvent];
  310.             break;
  311.         case RETURN:
  312.             [self _return: theEvent];
  313.             break;
  314.         case DELETE:
  315.             if ([[self delegate] respondsTo:@selector(delete:)])
  316.                 [[self delegate] delete:self];
  317.             break;
  318.         default:
  319.             if (theEvent->data.key.repeat) return self;
  320.             sprintf (searchString, "%s%c", searchString, theEvent->data.key.charCode);
  321.             if (! (strlen (searchString) % (CHUNK - 1))) [self _chunk];
  322.             [self _addTimedEntry];
  323.             break;
  324.         }
  325.         
  326.     return self;
  327. }
  328.  
  329.  
  330. - (BOOL)acceptsFirstResponder
  331. {
  332.     return YES;
  333. }
  334.  
  335.  
  336. //----------------------------------------------------------------------------------------------------
  337. //    Archiving Methods
  338. //----------------------------------------------------------------------------------------------------
  339. - read: (NXTypedStream*) stream
  340. {
  341.     [super read: stream];
  342.     NXReadTypes (stream, "cf", &wantsCaseSensitiveSearch, &inputTimeOut);
  343.     return self;
  344. }
  345.  
  346.  
  347. - write: (NXTypedStream*) stream
  348. {
  349.     [super write: stream];
  350.     NXWriteTypes (stream, "cf", &wantsCaseSensitiveSearch, &inputTimeOut);
  351.     return self;
  352. }
  353.  
  354.  
  355. - awake
  356. {
  357.     [super awake];
  358.     [self _chunk];
  359.     memset (searchString, 0, CHUNK);
  360.     return self;
  361. }
  362.  
  363.  
  364. //----------------------------------------------------------------------------------------------------
  365. //    Superclass Overrides
  366. //----------------------------------------------------------------------------------------------------
  367. - acceptArrowKeys:(BOOL)acceptFlag andSendActionMessages:(BOOL)sendFlag
  368. {
  369.     [super acceptArrowKeys:YES andSendActionMessages:sendFlag];
  370.     return self;
  371. }
  372.  
  373.  
  374. - acceptArrowKeys:(BOOL)acceptFlag
  375. {
  376.     //  2.1 method.
  377.     [super acceptArrowKeys:YES andSendActionMessages:YES];
  378.     return self;
  379. }
  380.  
  381.  
  382. //---------------------------------------------------------------------------------------------------------
  383. //     IB Methods
  384. //---------------------------------------------------------------------------------------------------------
  385. - (const char*) getInspectorClassName
  386. {
  387.     return "KeyDownBrowserInspector";
  388. }
  389.  
  390.  
  391. @end